import decimal
from pickle import FALSE
from xmlrpc.client import Fault
from jt32.settings import alipy
from django.db import transaction
from django.shortcuts import render
from rest_framework import viewsets, permissions, status, serializers
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from shopping.models import Classification, Commodity,CommodityImg,ShoppingCart,Order,OrderGoods,Payment
from shopping.serializers import ClassificationSerializer, ClassificationSerializerSimple, CommoditySerializer, \
    ShoppingCartSerializer,OrderSerializer,PaymentSerializer
from users.models import Address
# 导入 fastdfs
from fdfs_client.client import Fdfs_client,get_tracker_conf
import random
from datetime import datetime

#根据配置信息得到 连接信息地址 连接fastdfs
client = get_tracker_conf("fastdfs/client.conf")
# 得到客户端对象
client = Fdfs_client(client)
import logging
# 得到日志对象
logger = logging.getLogger(__name__)

# Create your views here.

class ClassificationViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Classification.objects.all()
    serializer_class = ClassificationSerializer
    permission_classes = [permissions.IsAuthenticated]

    # 查看所有分类的时候
    # 应该展示的一级分类
    # 指定id 1  ==》 python基础里面的  子级分类展示出来

    # 查询集
    # 如果是 list方法 就展示 没有父级的  分类数据

    #重写查询集
    def get_queryset(self):
        if self.action in ['list']:
            return Classification.objects.filter(parent__isnull=True)
        return self.queryset

    def get_serializer_class(self):
        if self.action in ['list']:
            return ClassificationSerializerSimple
        # return ClassificationSerializer
        return self.serializer_class

    # @action(detail=True, methods=['get'])
    # def commodity(self,request,*args,**kwargs):
    #     #获取分类的数据
    #     try:
    #         classifications = self.get_queryset().get(pk=kwargs['pk'])
    #     except Classification.DoesNotExist:
    #         return Response(status=status.HTTP_404_NOT_FOUND)
    #
    #     #判断一级分类或者二级分类
    #     # 乐观的假设 提前用filter_field 保存要操作的字段名
    #     filter_fileld = 'classification1_set'
    #     classifications_name = classifications.name
    #     if classifications.parent:
    #         #二级分类
    #         filter_fileld = 'classification2_set'
    #         classifications_name = f"{classifications.parent.name}--{classifications.name}"
    #
    #     #根据分类模型 获取商品数据
    #     commodityres = getattr(classifications, filter_fileld)
    #     #序列化返回
    #     commodityserializer = CommoditySerializer(commodityres, many=True)
    #     return Response({
    #         'commodity': commodityserializer.data,
    #         'classification':classifications_name,
    #     })

    @action(methods=["get"], detail=True)
    def commodity(self, request, pk):
        # 获取分类的数据
        try:
            # classificationres模型对象
            # classificationres = self.queryset.get(id=pk)
            classificationres = self.get_queryset().get(id=pk)
        except Classification.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)

        # 乐观的假设 提前用filter_field 保存要操作的字段名
        filter_field = "classification1"
        classificationres_name = classificationres.name
        # 怎么判断是一级分类 还是二级分类呢
        if classificationres.parent:
            # 二级分类
            filter_field = "classification2"
            classificationres_name = f"{classificationres.parent.name}--{classificationres.name}"

        # 查询方法

        filter_kwargs = {
            filter_field: classificationres,
            "is_delete": False,
            "status": 1
        }
        # Commodity.objects.filter(classification1 = 分类模型)
        # Commodity.objects.filter(classification2 = 分类模型)
        # Commodity.objects.filter(classification2_id = 分类模型id)
        # 不是反向查询  商品 查询 分类的
        #
        commodityres = Commodity.objects.filter(**filter_kwargs)

        commodityserializer = CommoditySerializer(commodityres, many=True)
        return Response({
            "commodity": commodityserializer.data,
            "classification": classificationres_name
        })


#商品视图
class CommodityViewSet(viewsets.ModelViewSet):
    queryset = Commodity.objects.all()
    serializer_class = CommoditySerializer
    permission_classes = [permissions.IsAuthenticated]

    # 重写 create方法
    # 二个模型的数据存储
    def create(self, request, *args, **kwargs):
        # 得到前端传入的商品数据 商品分类的id数据
        # request.data  反序列化  校验
        # 创建
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 商品图片的存储  getlist 多个图片数据
        files = request.FILES.getlist('file')

        for file in files:  # file 单独的图片
            if file:
                # 判断是不是图片数据
                if file.content_type not in ["image/png", "image/jpeg"]:
                    # 不是图片报错异常
                    return Response({"detail": "仅支持png或者jpg的格式"}, status=status.HTTP_400_BAD_REQUEST)

                # 获取文件后缀  xxx.png  xxx.jpg
                try:
                    image_ext_name = file.name.split('.')[-1]
                except Exception as e:
                    logger.info(f"图片扩展名异常 {e}")
                    image_ext_name = "png"
                # 上传到fastdfs
                try:
                    upload_res = client.upload_by_buffer(file.read(), file_ext_name=image_ext_name)
                except Exception as e:
                    logger.error(f"图片上传异常{e}")
                    return Response({"detail": "图片上传错误"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                # 判断是否成功
                if upload_res.get("Status") != "Upload successed.":
                    logger.error(f"图片上传失败")
                    return Response({"detail": "图片上传失败"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                # 得到新头像的地址                       decode() 解码成字符数据
                image_url = upload_res.get("Remote file_id").decode()

                # 图片存储进入的 图模型当中
                CommodityImg.objects.create(src=image_url, commodity_id=serializer.data["id"])

        return Response(serializer.data)

    @action(detail=False, methods=['get'])
    def optimization(self, request):
        # 展示优选商品  排序操作
        # 得到所有的商品数据  进行排序   考前的展示出来
        # queryset = Commodity.objects.all().order_by('-sales').order_by('-comments')
        queryset = self.get_queryset().order_by('-sales').order_by('-comments')
        if len(queryset) >=5:
            queryset = queryset[:5]
        #序列化返回
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

#购物车视图
class ShoppingCartViewSet(viewsets.ModelViewSet):
    queryset = ShoppingCart.objects.all()
    serializer_class = ShoppingCartSerializer
    permission_classes = [permissions.IsAuthenticated]

    #避免查看到别人的购物车
    def get_queryset(self):
        return self.request.user.shoppingcart_set.all()

    def create(self, request, *args, **kwargs):
        request.POST._mutable = True
        request.data["user"] = request.user.id
        commodity_id = request.data["commodity"]
        number = request.data["number"]
        #判断该商品之前有没有添加过
        existing_item = ShoppingCart.objects.filter(user = request.user, commodity_id = commodity_id).first()

        if existing_item:
            #修改操作
            serializer = self.get_serializer(instance = existing_item,data={
                'user': request.user.id,
                'commodity': commodity_id,
                'number': existing_item.number + number
            })
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(serializer.data)
        else:
            return ModelViewSet.create(self,request, *args, **kwargs)

#订单视图
class OrderViewSet(viewsets.ModelViewSet):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer
    permission_classes = [permissions.IsAuthenticated]

    #当前用户只能看到自己的订单
    def get_queryset(self):
        return self.request.user.order_set.all()

    #重新写create方法
    # 针对一个功能函数，如果出现了多个修改  那么需要考虑  事务的操作

    def create(self, request, *args, **kwargs):
        #request.data = {address: 4, pay_method: "1", cart: ["1", "2"]}
        data = request.data
        user = request.user
        carts = data.get('cart')
        address_id = data.get('address')
        pay_method = data.get('pay_method')

        #校验购物车数据
        if not carts:
            return Response({"detail": "购物车为空"}, status=status.HTTP_400_BAD_REQUEST)
        #校验地址数据
        try:
            address = Address.objects.get(id=address_id)
        except Address.DoesNotExist:
            return Response({"detail": "地址不存在"}, status=status.HTTP_400_BAD_REQUEST)

        #如果存在——>地址模型得到具体的地址信息
        #省 市 区 详细地址 收件人 手机号
        address_res = f'''{address.province.name}
        {address.city.name}
        {address.district.name}
        【{address.mobile}】
        {address.place}'''

        #生成订单号
        order_id = datetime.now().strftime("%Y%m%d%H%M%S") + "%6d%2d"%(request.user.id,random.randint(0, 99))

        #开启事务
        with transaction.atomic():
            #初始点
            save_point = transaction.savepoint()
            try:
                order = Order.objects.create(
                    order_id=order_id,
                    pay_method=pay_method,
                    address=address_res,
                    status=1 if pay_method == '1' else 2,
                    total_count=0,
                    total_amount=decimal.Decimal(0),
                    user=user
                )

                for cart_id in carts:  # cart: ["1", "2"] 是购物车的id
                    while True:
                        # 通过购物车id获取商品id=》商品数据
                        try:
                            # cart --> 购物车模型
                            cart = ShoppingCart.objects.get(id=cart_id)
                        except ShoppingCart.DoesNotExist:
                            return Response({"detail": "购物的商品信息不存在"}, status=status.HTTP_400_BAD_REQUEST)
                        # 正向查询获取商品模型
                        commodity = cart.commodity

                        # 根据商品模型 获取数据
                        old_stock = commodity.stock
                        old_sales = commodity.sales

                        # 应该检查商品库存（因为加入购物车时候有库存，但是结算的时候不一定有库存）
                        if cart.number > old_stock:
                            raise ValidationError("库存不足")

                        # 购买后 库存减少 效率增加
                        new_stock = old_stock - cart.number  # 新库存  = 原来的库存 - 购买的数量
                        new_sales = old_sales + cart.number  # 新销量  = 原来的销量 + 购买的数量

                        # 商品表数据更新
                        # commodity.stock = new_stock
                        # commodity.sales = new_sales
                        # commodity.save()

                        # 判断数据是否发生变化
                        # 如果数据发生变化  那么久重新获取库存
                        # 乐观锁是逻辑
                        # update 更新成功  返回 1  如果更新失败 返回 0
                        res = Commodity.objects.filter(id=commodity.id,stock=old_stock).update(stock=new_stock, sales=new_sales)
                        if not res:
                            continue

                        # 订单模型也要同步进行更新
                        order.total_count += cart.number
                        order.total_amount += commodity.price * cart.number

                        OrderGoods.objects.create(
                            order=order,
                            number=cart.number,
                            price=commodity.price,
                            commodity=commodity
                        )
                        break
                    # 不在循环里面是因为要遍历全部商品后才保存订单，以替换上面所创建的空订单
                    # 订单保存
                    order.save()
            except Exception as e:
                #事务回滚
                transaction.savepoint_rollback(save_point)
                return Response({"detail": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            else:
                #事务提交
                transaction.savepoint_commit(save_point)

        #购物车清空
        ShoppingCart.objects.filter(id__in=carts).delete()
        serializer = self.get_serializer(order)
        return Response(serializer.data,status=status.HTTP_200_OK)

    @action(methods=['put'], detail=False)
    def status(self, request):
        data = request.query_params.dict()
        #订单号
        out_trade_no = data.get('out_trade_no')
        #交易号
        trade_id = data.get('trade_no')
        with transaction.atomic():
            save_point = transaction.savepoint()
            try:
                Payment.objects.create(trade_id = trade_id,order_id = out_trade_no)
                #修改订单状态
                self.get_queryset().filter(oder_id = out_trade_no,status = 1).update(status = 2)
            except Exception as e:
                transaction.savepoint_rollback(save_point)
                raise serializers.ValidationError({"detail": str(e)})
            else:
                transaction.savepoint_commit(save_point)
        return Response({"order_id": out_trade_no,"trade_id":trade_id}, status=status.HTTP_200_OK)


#支付视图
class PaymentViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Payment.objects.all()
    serializer_class = PaymentSerializer
    permission_classes = [permissions.IsAuthenticated]

    #http://127.0.0.1:8080/shopping/payments/20250703150056%20%20%20%20%20230/pay/
    @action(detail=True, methods=['get'])
    def pay(self, request, pk):
        #pk = 20250703150056%20%20%20%20%20230
        try:
            # 获取订单信息 必须是未支付的 并且是当前用户的
            order = Order.objects.get(order_id=pk,user=request.user,status=1)
        except Order.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)

        #配置参数
        order_res = alipy.api_alipay_trade_page_pay(
            subject = f"jutong系统",#标题
            out_trade_no = str(order.order_id),#订单号
            total_amount = str(order.total_amount),#总金额
            return_url = "http:127.0.0.1:8080/order/success", #跳转成功页面
        )

        #订单 金额
        pay_url = 'https://openapi-sandbox.dl.alipaydev.com/gateway.do?' + order_res

        #返回支付地址
        return Response({"pay_url": pay_url})








